﻿using DBUtil;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace Test.SqlServer
{
    /// <summary>
    /// 测试Id和流水号生成,基于分布式算法
    /// </summary>
    public sealed partial class GeneratorTests : TestBase
    {
        public GeneratorTests()
        {

        }
        #region 测试流水号
        [TestCategory("测试SNO生成-基于分布式")]
        [TestMethod]
        public void NewSNO_DistributeTest()
        {
            var sno = DotNetCommon.DistributeGenerator.NewSNO("test-test-sno", DotNetCommon.SerialFormat.CreateDistributeFast("SNO"));
            Assert.IsTrue(sno == "SNO" + DateTime.Now.ToString("yyyyMMdd") + DotNetCommon.Machine.MachineId.ToString().PadLeft(4, '0') + "000001");
            sno = DotNetCommon.DistributeGenerator.NewSNO("test-test-sno", DotNetCommon.SerialFormat.CreateDistributeFast("SNO"));
            Assert.IsTrue(sno == "SNO" + DateTime.Now.ToString("yyyyMMdd") + DotNetCommon.Machine.MachineId.ToString().PadLeft(4, '0') + "000002");
            //另一张表
            sno = DotNetCommon.DistributeGenerator.NewSNO("test-test2-sno", DotNetCommon.SerialFormat.CreateDistributeFast("SNO"));
            Assert.IsTrue(sno == "SNO" + DateTime.Now.ToString("yyyyMMdd") + DotNetCommon.Machine.MachineId.ToString().PadLeft(4, '0') + "000001");
            sno = DotNetCommon.DistributeGenerator.NewSNO("test-test2-sno", DotNetCommon.SerialFormat.CreateDistributeFast("SNO"));
            Assert.IsTrue(sno == "SNO" + DateTime.Now.ToString("yyyyMMdd") + DotNetCommon.Machine.MachineId.ToString().PadLeft(4, '0') + "000002");
        }

        [TestCategory("测试SNO生成-基于分布式-并发测试")]
        [TestMethod]
        public void NewSNOConcurrency_DistributeTest()
        {
            var tasks = new List<Task>();
            var snores = new System.Collections.Concurrent.ConcurrentQueue<(string sno, int threadid)>();
            for (int i = 0; i < 100; i++)
            {
                tasks.Add(Task.Factory.StartNew(() =>
                {
                    for (int j = 0; j < 100; j++)
                    {
                        var sno = DotNetCommon.DistributeGenerator.NewSNO("test-test-sno", DotNetCommon.SerialFormat.CreateDistributeFast("SNO"));
                        snores.Enqueue((sno, Thread.CurrentThread.ManagedThreadId));
                    }
                }, TaskCreationOptions.LongRunning));
            }
            Task.WaitAll(tasks.ToArray());
            var list = snores.ToList();
            list = list.OrderByDescending(t => t.sno).ToList();
            var expactCount = 100 * 100;
            Assert.IsTrue(list.FirstOrDefault().sno == $"SNO{DateTime.Now.ToString("yyyyMMdd")}{DotNetCommon.Machine.MachineId.ToString().PadLeft(4, '0')}{expactCount.ToString().PadLeft(6, '0')}");
            Assert.IsTrue(list.Count == expactCount);
        }

        #endregion

        #region 测试Id生成
        [TestCategory("Id生成-基于分布式")]
        [TestMethod]
        public void NewId_DistributeTest()
        {
            long id = DotNetCommon.DistributeGenerator.NewId("test-test-id");
            Assert.IsTrue(id > 0);
            Assert.IsTrue(id.ToString().Length > 6);

            long id2 = DotNetCommon.DistributeGenerator.NewId("test-test2-id");
            Assert.IsTrue(id2 > 0);
            Assert.IsTrue(id2.ToString().Length > 6);

            long id3 = DotNetCommon.DistributeGenerator.NewId("test-test-id");
            Assert.IsTrue(id3 > 0);
            Assert.IsTrue(id3.ToString().Length > 6);

            long id4 = DotNetCommon.DistributeGenerator.NewId("test-test2-id");
            Assert.IsTrue(id4 > 0);
            Assert.IsTrue(id4.ToString().Length > 6);

            Assert.IsTrue(id3 > id);
            Assert.IsTrue(id4 > id2);
            Assert.IsTrue(id == id2);
            Assert.IsTrue(id3 == id4);
        }

        [TestCategory("Id生成-基于分布式-并发测试")]
        [TestMethod]
        public void NewIdConcurrency_DistributeTest()
        {
            var tasks = new List<Task>();
            var idres = new System.Collections.Concurrent.ConcurrentQueue<(long id, int threadid)>();
            for (int i = 0; i < 100; i++)
            {
                tasks.Add(Task.Factory.StartNew(() =>
                {
                    try
                    {
                        for (int j = 0; j < 100; j++)
                        {
                            long idg = 0;
                            if (j % 2 == 0)
                            {
                                var db2 = db.CreateNewDB();
                                idg = DotNetCommon.DistributeGenerator.NewId("test-test-id");
                            }
                            else
                            {
                                idg = DotNetCommon.DistributeGenerator.NewId("test-test-id");
                            }
                            idres.Enqueue((idg, Thread.CurrentThread.ManagedThreadId));
                        }
                    }
                    catch (Exception ex)
                    {
                        Debug.Write(ex?.Message + ex?.StackTrace);
                        Debug.Fail(ex?.Message, ex?.StackTrace);
                    }
                }, TaskCreationOptions.LongRunning));
            }
            Task.WaitAll(tasks.ToArray());
            var list = idres.ToList();

            var g = list.GroupBy(i => i.id).Where(i => i.Count() > 1).ToList();
            Assert.IsTrue(g.Count == 0);

            list = list.OrderByDescending(t => t.id).ToList();
            var expactCount = 100 * 100;
            Assert.IsTrue(list.Count == expactCount);
        }
        #endregion
    }
}
